import _thread
import time
from tkinter.simpledialog import askstring

import cv2
import numpy
import pyscreeze as pyscreeze
from PIL import ImageGrab

from common import *
import tkinter as tk
from tkinter import ttk, messagebox

from entity.Image import *


class ImageTool(Window):
    def __init__(self, ddt):
        super().__init__()
        self.root = ddt
        self.window = ddt.image_tool
        self.title = "抓图工具"
        self.WIDTH = 0
        self.HEIGHT = 0

        """定义变量"""
        self.tip = tk.StringVar()
        self.combobox = None
        self.desc = tk.StringVar()
        self.threshold = tk.StringVar()
        self.threshold.set("0.95")
        # 图片缓存
        self.image = None
        # 鼠标点击的坐标
        self.point1 = None
        # 鼠标释放的坐标
        self.point2 = None
        # 特征缓存
        self.Image = Image()
        # 是否测试
        self.is_test = False

        """绑定事件"""
        # 窗口关闭事件
        self.window.protocol("WM_DELETE_WINDOW", self.exit)

        """加载组件"""
        self.set_window()

        """判断是否有Image对象传入"""
        if self.root.Image is not None:
            self.init()

    def init(self):
        """初始化"""
        if self.Image is None:
            return 1
        self.Image = self.root.Image
        self.combobox.set(self.Image.scene)
        self.desc.set(self.Image.desc)
        self.threshold.set(self.Image.threshold)

    def exit(self):
        """抓图工具退出"""
        self.hide()
        self.root.show()
        # 销毁窗口
        self.window.destroy()

    def set_tip(self):
        """提示功能"""
        tip_label = tk.Label(self.window, textvariable=self.tip)
        tip_label.grid(row=0, column=0, columnspan=3)
        self.tip.set("选择场景以编辑特征")

    def reset_combobox_list(self):
        """重新获取下拉框值"""
        self.combobox["value"] = [x.name for x in self.root.project.project.iterdir() if x.is_dir()]

    def set_combobox(self):
        """下拉框设置"""
        combobox_label = tk.Label(self.window, text="场景")
        combobox = ttk.Combobox(self.window, state="readonly", width=17)
        self.combobox = combobox
        # 绑定函数
        combobox.bind("<<ComboboxSelected>>", self.select_scene)
        combobox["value"] = [x.name for x in self.root.project.project.iterdir() if x.is_dir()]
        combobox_button = tk.Button(self.window, text="新增", command=self.add_scene)
        combobox_label.grid(row=1, column=0)
        combobox.grid(row=1, column=1)
        combobox_button.grid(row=1, column=2)

    def select_scene(self, event):
        self.tip.set(f"已选择场景‘{self.combobox.get()}’")

    def set_information(self):
        """特征信息"""
        desc_label = tk.Label(self.window, text="描述", pady=20)
        desc_entry = tk.Entry(self.window, textvariable=self.desc, width=20)
        # 绑定光标事件
        desc_entry.bind("<Enter>", lambda x: self.tip.set(f"输入该特征的描述信息"))
        desc_label.grid(row=2, column=0)
        desc_entry.grid(row=2, column=1)

        threshold_label = tk.Label(self.window, text="阈值")
        threshold_entry = tk.Entry(self.window, textvariable=self.threshold)
        # 绑定光标事件
        threshold_entry.bind("<Enter>", lambda x: self.tip.set(f"特征对比的相似度，低于0.9会误识别"))
        threshold_label.grid(row=3, column=0)
        threshold_entry.grid(row=3, column=1)

    def set_screenshot(self):
        """截图功能"""
        screenshot_button = tk.Button(self.window, text="截图", command=self.screenshot)
        screenshot_button.bind("<Enter>", lambda x: self.tip.set("点击截取图片特征"))
        screenshot_button.grid(row=4, column=0, pady=10)

    def set_test(self):
        """测试功能"""
        test_button = tk.Button(self.window, text="测试", command=self.test)
        test_button.grid(row=4, column=1)

    def set_load(self):
        """载入功能"""
        load_button = tk.Button(self.window, text="载入", command=self.load)
        load_button.grid(row=4, column=2)

    def load(self):
        if not self.is_test:
            self.tip.set("还没有测试过图片特征，请测试！")
            messagebox.showwarning("提示", "还没有测试过图片特征，请测试")
            return 0
        self.exit()
        self.root.open_type = False
        self.root.get_image_to_ddt()

    def test(self):
        if self.image is None:
            self.tip.set("没有图片缓存，请先截图")
            messagebox.showwarning("提示", "没有图片缓存，请先截图")
            return 0
        # 全屏截图
        pyscreeze.screenshot("screen.jpg")
        # 灰度识别
        screen = cv2_read("screen.jpg")
        # 寻找图片坐标
        _res = image_to_position(screen, gray(self.image))
        # 解析坐标
        max_loc = _res[1]
        image_x = float(_res[2])
        image_y = float(_res[3])
        # 判断
        if float(_res[0]) >= float(self.Image.threshold):
            self.is_test = True
            self.hide()
            messagebox.showinfo(title='识别结果',
                                message='识别到物体\n识别率为：' +
                                str(_res[0]) + "坐标为："
                                + str(float(max_loc[0]) + image_y / 2) + "," +
                                str(float(max_loc[1]) + image_x / 2))
        else:
            self.hide()
            messagebox.showwarning(title='识别率',
                                   message='该阈值无法识别到物体\n识别率为：'
                                           + str(_res[0]))
        self.show()

    def screenshot(self):
        if self.combobox.get() == "" or self.combobox.get() is None:
            self.tip.set("请选择场景")
            self.hide()
            messagebox.showwarning("提示", "还没有选择场景，请选择")
            self.show()
            return 0
        if self.desc.get() == "" or self.desc.get() is None:
            self.tip.set("请输入描述信息")
            self.hide()
            messagebox.showwarning("提示", "还没有输入描述信息，请输入")
            self.show()
            return 0
        if self.threshold.get() == "" or self.threshold.get() is None:
            self.tip.set("请输入识别阈值，建议9.5以上")
            self.hide()
            messagebox.showwarning("提示", "还没有识别阈值，请输入，建议0.95以上")
            self.show()
            return 0
        if not is_number(self.threshold.get()):
            self.tip.set("识别阈值只能是数字")
            self.hide()
            messagebox.showwarning("提示", "识别阈值只能是数字，已自动赋值0.95")
            self.threshold.set("0.95")
            self.show()
            return 0
        if pathlib.Path(self.get_image_path()).is_file():
            self.hide()
            if not messagebox.askyesno("提示", "已有该特征，是否覆盖原文件？"):
                self.tip.set("截图已取消")
                self.show()
                return 0
            time.sleep(0.5)
            self.show()
        self.hide()

        _thread.start_new_thread(self.screenshot_thread, ())

    def screenshot_thread(self):
        """截图功能"""
        self.image = cv2.cvtColor(numpy.asarray(ImageGrab.grab()), cv2.COLOR_RGB2BGR)
        cv2.namedWindow("image", cv2.WINDOW_KEEPRATIO)
        cv2.setWindowProperty("image", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
        cv2.setMouseCallback("image", self.on_mouse)
        cv2.imshow("image", self.image)
        cv2.waitKey(0)
        self.show()

    def on_mouse(self, event, x, y, flags, param):
        """截图实现"""
        image_copy = self.image.copy()
        if event == cv2.EVENT_LBUTTONDOWN:  # 左键点击
            self.point1 = (x, y)
            cv2.circle(image_copy, self.point1, 10, (0, 255, 0), 5)
            cv2.imshow('image', image_copy)
        elif event == cv2.EVENT_MOUSEMOVE and (flags & cv2.EVENT_FLAG_LBUTTON):  # 按住左键拖曳
            cv2.rectangle(image_copy, self.point1, (x, y), (255, 0, 0), 5)
            cv2.imshow('image', image_copy)
        elif event == cv2.EVENT_LBUTTONUP:  # 左键释放
            self.point2 = (x, y)
            cv2.rectangle(image_copy, self.point1, self.point2, (0, 0, 255), 5)
            cv2.imshow('image', image_copy)
            min_x = min(self.point1[0], self.point2[0])
            min_y = min(self.point1[1], self.point2[1])
            width = abs(self.point1[0] - self.point2[0])
            height = abs(self.point1[1] - self.point2[1])
            self.image = self.image[min_y:min_y + height, min_x:min_x + width]
            self.save_img()
            cv2.destroyWindow("image")

    def get_image_path(self):
        image_path = self.root.project.project / self.combobox.get()
        image_path = str(image_path) + "/" + self.desc.get() + ".jpg"
        return image_path

    def save_img(self):
        """保存截图"""
        # 信息保存至Image对象
        image_path = self.get_image_path()
        self.Image.project_name = self.root.project.name
        self.Image.path = pathlib.Path(image_path)
        self.Image.scene = self.combobox.get()
        self.Image.desc = self.desc.get()
        self.Image.threshold = self.threshold.get()
        # 数据传递给ddt
        self.root.Image = self.Image
        # 保存图片至本地
        try:
            cv2.imencode(".jpg", self.image)[1].tofile(image_path)
        except cv2.error:
            self.tip.set("截图取消")

    def set_function(self):
        """重写功能"""
        # 窗口置顶弹出
        self.window.wm_attributes('-topmost', 1)
        # 禁止拉伸
        self.window.resizable(0, 0)
        # 去掉窗口最大化最小化按钮，只保留关闭
        self.window.attributes("-toolwindow", 2)
        # 提示栏
        self.set_tip()
        # 场景选择框
        self.set_combobox()
        # 关键信息
        self.set_information()
        # 截图功能
        self.set_screenshot()
        # 识图测试功能
        self.set_test()
        # 载入操作
        self.set_load()

    def add_scene(self):
        self.root.window.state("normal")
        self.hide()
        scene_name = askstring(title="请输入新场景名称", prompt="场景名")
        if scene_name is not None:
            scene_path = self.root.project.project / scene_name
            scene_path.mkdir()
        self.show()
        self.reset_combobox_list()
        self.root.window.state("iconic")

